package com.acme.ioniolab.serialization;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;

import com.acme.ioniolab.serialization.implementations.GsonSerializer;
import com.acme.ioniolab.serialization.implementations.PlainSerializer;
import com.acme.ioniolab.serialization.implementations.ProtobufSerializer;
import com.acme.ioniolab.serialization.implementations.XstreamSerializer;

public class SerializationTest {
	private static final int NUM_OBJECTS = 100;

	public static void main(String[] args) throws InterruptedException {
		if (args.length < 2) {
			System.out.println("Usage: srv port\nOR \n cl remotehost port");
			return;
		}
		if ("srv".equals(args[0])) {
			server(new PlainSerializer(), Integer.parseInt(args[1]));
			Thread.sleep(500);
			server(new GsonSerializer(), Integer.parseInt(args[1]));
			Thread.sleep(500);
			server(new XstreamSerializer(), Integer.parseInt(args[1]));
			Thread.sleep(500);
			server(new ProtobufSerializer(), Integer.parseInt(args[1]));
		}
		if ("cl".equals(args[0])) {
			client(new PlainSerializer(), args[1], Integer.parseInt(args[2]));
			Thread.sleep(1000);
			client(new GsonSerializer(), args[1], Integer.parseInt(args[2]));
			Thread.sleep(1000);
			client(new XstreamSerializer(), args[1], Integer.parseInt(args[2]));
			Thread.sleep(1000);
			client(new ProtobufSerializer(), args[1], Integer.parseInt(args[2]));
		}
	}

	private static void server(Serializer serializer, int port) {
		
		try (ServerSocket serverSocket = new ServerSocket(port);
				Socket socket = serverSocket.accept();
				ObjectOutputStream objectOutputStream = new ObjectOutputStream(
						socket.getOutputStream());
				ObjectInputStream objectInputStream = new ObjectInputStream(
						socket.getInputStream())) {
			
			long start = System.currentTimeMillis();
			serializer.deserialize(objectInputStream.readObject());
			objectOutputStream.writeObject("done");
			long singleObjTime = System.currentTimeMillis() - start;
			
			start = System.currentTimeMillis();
			int num = objectInputStream.readInt();
			SensorData[] objectArray = new SensorData[num];
			for (int i = 0; i < num; i++) {
				objectArray[i] = (SensorData) serializer.deserialize(objectInputStream.readObject());
			}
			objectOutputStream.writeObject("done");
			
			long time = System.currentTimeMillis() - start;

			System.out.printf("Server, %s: %d ms per one object\n", serializer.getType(),	singleObjTime);
			System.out.printf("Server, %s: %f objects per second\n",
					serializer.getType(), ((double) num) / time);
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	private static void client(Serializer serializer, String host, int port) {
		try (Socket socket = new Socket(host, port);
				ObjectOutputStream objectOutputStream = new ObjectOutputStream(
						socket.getOutputStream());
				ObjectInputStream objectInputStream = new ObjectInputStream(
						socket.getInputStream())) {

			long start = System.currentTimeMillis();
			objectOutputStream.writeObject(serializer.serialize(new SensorData()));
			objectInputStream.readObject();
			long singleObjTime = System.currentTimeMillis() - start;

			objectOutputStream.writeInt(NUM_OBJECTS);
			start = System.currentTimeMillis();
			for (int i = 0; i < NUM_OBJECTS; i++) {
				objectOutputStream.writeObject(serializer.serialize(new SensorData()));
			}
			objectInputStream.readObject();
			long time = System.currentTimeMillis() - start;

			System.out.printf("%s: %d ms per one object\n", serializer.getType(),
					singleObjTime);
			System.out.printf("%s: %f objects per second\n",
					serializer.getType(), ((double) NUM_OBJECTS) / time);

		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
